{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Welcome to the first SimpleITK Notebook demo:\n",
    "# SimpleITK Image Basics\n",
    "\n",
    "This document will give a brief orientation to the SimpleITK Image class.\n",
    "\n",
    "First we import the SimpleITK Python module. By convention our module is imported into the shorter and more Pythonic \"sitk\" local name.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import SimpleITK as sitk\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Image Construction\n",
    "\n",
    "There are a variety of ways to create an image. All images' initial value is well defined as zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "image = sitk.Image(256, 128, 64, sitk.sitkInt16)\n",
    "image_2D = sitk.Image(64, 64, sitk.sitkFloat32)\n",
    "image_2D = sitk.Image([32,32], sitk.sitkUInt32)\n",
    "image_RGB = sitk.Image([128,128], sitk.sitkVectorUInt8, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pixel Types\n",
    "\n",
    "The pixel type is represented as an enumerated type. The following is a table of the enumerated list.\n",
    "\n",
    "<table>\n",
    "  <tr><td>sitkUInt8</td><td>Unsigned 8 bit integer</td></tr>\n",
    "  <tr><td>sitkInt8</td><td>Signed 8 bit integer</td></tr>\n",
    "  <tr><td>sitkUInt16</td><td>Unsigned 16 bit integer</td></tr>\n",
    "  <tr><td>sitkInt16</td><td>Signed 16 bit integer</td></tr>\n",
    "  <tr><td>sitkUInt32</td><td>Unsigned 32 bit integer</td></tr>\n",
    "  <tr><td>sitkInt32</td><td>Signed 32 bit integer</td></tr>\n",
    "  <tr><td>sitkUInt64</td><td>Unsigned 64 bit integer</td></tr>\n",
    "  <tr><td>sitkInt64</td><td>Signed 64 bit integer</td></tr>\n",
    "  <tr><td>sitkFloat32</td><td>32 bit float</td></tr>\n",
    "  <tr><td>sitkFloat64</td><td>64 bit float</td></tr>\n",
    "  <tr><td>sitkComplexFloat32</td><td>complex number of 32 bit float</td></tr>\n",
    "  <tr><td>sitkComplexFloat64</td><td>complex number of 64 bit float</td></tr>\n",
    "  <tr><td>sitkVectorUInt8</td><td>Multi-component of unsigned 8 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorInt8</td><td>Multi-component of signed 8 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorUInt16</td><td>Multi-component of unsigned 16 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorInt16</td><td>Multi-component of signed 16 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorUInt32</td><td>Multi-component of unsigned 32 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorInt32</td><td>Multi-component of signed 32 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorUInt64</td><td>Multi-component of unsigned 64 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorInt64</td><td>Multi-component of signed 64 bit integer</td></tr>\n",
    "  <tr><td>sitkVectorFloat32</td><td>Multi-component of 32 bit float</td></tr>\n",
    "  <tr><td>sitkVectorFloat64</td><td>Multi-component of 64 bit float</td></tr>\n",
    "  <tr><td>sitkLabelUInt8</td><td>RLE label of unsigned 8 bit integers</td></tr>\n",
    "  <tr><td>sitkLabelUInt16</td><td>RLE label of unsigned 16 bit integers</td></tr>\n",
    "  <tr><td>sitkLabelUInt32</td><td>RLE label of unsigned 32 bit integers</td></tr>\n",
    "  <tr><td>sitkLabelUInt64</td><td>RLE label of unsigned 64 bit integers</td></tr>\n",
    "</table>\n",
    "\n",
    "There is also `sitkUnknown`, which is used for undefined or erroneous pixel ID's. It has a value of -1.\n",
    "\n",
    "The 64-bit integer types are not available on all distributions. When not available the value is `sitkUnknown`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### More Information about the Image class be obtained in the Docstring\n",
    "\n",
    "\n",
    "SimpleITK classes and functions have the Docstrings derived from the C++ definitions and the Doxygen documentation. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "help(image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Accessing Attributes\n",
    "\n",
    "If you are familiar with ITK, then these methods will follow your expectations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image.GetSize())\n",
    "print(image.GetOrigin())\n",
    "print(image.GetSpacing())\n",
    "print(image.GetDirection())\n",
    "print(image.GetNumberOfComponentsPerPixel())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note: The starting index of a SimpleITK Image is always 0. If the output of an ITK filter has non-zero starting index, then the index will be set to 0, and the origin adjusted accordingly.\n",
    "\n",
    "The size of the image's dimensions have explicit accessors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image.GetWidth())\n",
    "print(image.GetHeight())\n",
    "print(image.GetDepth())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since the dimension  and pixel type of a SimpleITK image is determined at run-time accessors are needed. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image.GetDimension())\n",
    "print(image.GetPixelIDValue())\n",
    "print(image.GetPixelIDTypeAsString())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the depth of a 2D image?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image_2D.GetSize())\n",
    "print(image_2D.GetDepth())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What is the dimension and size of a Vector image?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image_RGB.GetDimension())\n",
    "print(image_RGB.GetSize())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image_RGB.GetNumberOfComponentsPerPixel())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For certain file types such as DICOM, additional information about the image is contained in the meta-data dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "for key in image.GetMetaDataKeys():\n",
    "        print(\"\\\"{0}\\\":\\\"{1}\\\"\".format(key, image.GetMetaData(key)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Accessing Pixels\n",
    "\n",
    "There are the member functions ``GetPixel`` and ``SetPixel`` which provides an ITK-like interface for pixel access."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "help(image.GetPixel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image.GetPixel(0, 0, 0))\n",
    "image.SetPixel(0, 0, 0, 1)\n",
    "print(image.GetPixel(0, 0, 0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(image[0,0,0])\n",
    "image[0,0,0] = 10\n",
    "print(image[0,0,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conversion between numpy and SimpleITK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "nda = sitk.GetArrayFromImage(image)\n",
    "print(nda)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "help(sitk.GetArrayFromImage)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Get a view of the image data as a numpy array, useful for display\n",
    "nda = sitk.GetArrayViewFromImage(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "nda = sitk.GetArrayFromImage(image_RGB)\n",
    "img = sitk.GetImageFromArray(nda)\n",
    "img.GetSize()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "help(sitk.GetImageFromArray)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "img = sitk.GetImageFromArray(nda, isVector=True)\n",
    "print(img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The order of index and dimensions need careful attention during conversion\n",
    "\n",
    "ITK's Image class does not have a bracket operator. It has a GetPixel which takes an ITK Index object as an argument, which is ordered as ``(x,y,z)``. This is the convention that SimpleITK's Image class uses for the GetPixel method and slicing operator as well. In numpy, an array is indexed in the **opposite** order ``(z,y,x)``. Also note that the access to channels is different. In SimpleITK you do not access the channel directly, rather the pixel value representing all channels for the specific pixel is returned and you then access the channel for that pixel. In the numpy array you are accessing the channel directly. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "multi_channel_3Dimage = sitk.Image([2,4,8], sitk.sitkVectorFloat32, 5)\n",
    "x = multi_channel_3Dimage.GetWidth() - 1\n",
    "y = multi_channel_3Dimage.GetHeight() - 1\n",
    "z = multi_channel_3Dimage.GetDepth() - 1\n",
    "multi_channel_3Dimage[x,y,z] = np.random.random(multi_channel_3Dimage.GetNumberOfComponentsPerPixel())\n",
    "\n",
    "nda = sitk.GetArrayFromImage(multi_channel_3Dimage)\n",
    "\n",
    "print(\"Image size: \" + str(multi_channel_3Dimage.GetSize()))\n",
    "print(\"Numpy array size: \" + str(nda.shape))\n",
    "\n",
    "# Notice the index order and channel access are different:\n",
    "print(\"First channel value in image: \" + str(multi_channel_3Dimage[x,y,z][0]))\n",
    "print(\"First channel value in numpy array: \" + str(nda[z,y,x,0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Are we still dealing with Image, because I haven't seen one yet...\n",
    "\n",
    "While SimpleITK does not do visualization, it does contain a built in ``Show`` method. This function writes the image out to disk and than launches a program for visualization. By default it is configured to use ImageJ, because it is readily supports all the image types which SimpleITK has and load very quickly. However, it's easily customizable by setting environment variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "simpleitk_error_allowed": "Exception thrown in SimpleITK Show:"
   },
   "outputs": [],
   "source": [
    "sitk.Show(image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sitk.Show?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By converting into a numpy array, matplotlib can be used for visualization for integration into the scientific python environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "z = 0\n",
    "slice = sitk.GetArrayViewFromImage(image)[z,:,:]\n",
    "plt.imshow(slice)"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [default]",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
